home *** CD-ROM | disk | FTP | other *** search
/ Aminet 28 / Aminet 28 (1998)(GTI - Schatztruhe)[!][Dec 1998].iso / Aminet / dev / c / qtools0.2-src.lha / src / libqtools / map.c < prev    next >
Encoding:
C/C++ Source or Header  |  1998-07-15  |  22.8 KB  |  947 lines

  1. #define    LIBQTOOLS_CORE
  2. #include "../include/libqtools.h"
  3. #include "../include/libqbuild.h"
  4.  
  5. char token[MAXTOKEN];                        /* 128 */
  6. bool unget;                            /* ? */
  7. char *script_p;                            /* 4 */
  8. int scriptline;                            /* 4 */
  9. struct entity *mapent;                        /* 4 */
  10. int nummapbrushes;                        /* 4 */
  11. short int numlighttargets;
  12. char lighttargets[32][64];
  13.  
  14. vec3_t baseaxis[18] =                        /* 216 */
  15. {
  16.   {0, 0, 1},
  17.   {1, 0, 0},
  18.   {0, -1, 0},                            /* floor */
  19.   {0, 0, -1},
  20.   {1, 0, 0},
  21.   {0, -1, 0},                            /* ceiling */
  22.   {1, 0, 0},
  23.   {0, 1, 0},
  24.   {0, 0, -1},                            /* west wall */
  25.   {-1, 0, 0},
  26.   {0, 1, 0},
  27.   {0, 0, -1},                            /* east wall */
  28.   {0, 1, 0},
  29.   {1, 0, 0},
  30.   {0, 0, -1},                            /* south wall */
  31.   {0, -1, 0},
  32.   {1, 0, 0},
  33.   {0, 0, -1}                            /* north wall */
  34. };
  35.  
  36. /*============================================================================ */
  37.  
  38. /*
  39.  * ===============
  40.  * FindMiptex
  41.  * 
  42.  * ===============
  43.  */
  44. int FindMiptex(__memBase, char *name)
  45. {
  46.   int i;
  47.  
  48.   for (i = 0; i < bspMem->nummaptexstrings; i++) {
  49.     if (!__strcasecmp(name, bspMem->maptexstrings[i]))
  50.       return i;
  51.   }
  52.   if (bspMem->nummaptexstrings == bspMem->max_nummaptexstrings)
  53.     ExpandClusters(bspMem, MAP_TEXSTRINGS);
  54.   __strncpy(bspMem->maptexstrings[i], name, 16);
  55.   bspMem->nummaptexstrings++;
  56.   return i;
  57. }
  58.  
  59. /*
  60.  * ===============
  61.  * FindTexinfo
  62.  * 
  63.  * Returns a global texinfo number
  64.  * ===============
  65.  */
  66. int FindTexinfo(__memBase, struct texinfo *t)
  67. {
  68.   int i, j;
  69.   struct texinfo *tex;
  70.  
  71.   /* set the special flag */
  72.   if (bspMem->maptexstrings[t->miptex][0] == '*' || !__strncasecmp(bspMem->maptexstrings[t->miptex], "sky", 3))
  73.     t->flags |= TEX_SPECIAL;
  74.  
  75.   tex = bspMem->shared.quake1.texinfo;
  76.   for (i = 0; i < bspMem->shared.quake1.numtexinfo; i++, tex++) {
  77.     if (t->miptex != tex->miptex)
  78.       continue;
  79.     if (t->flags != tex->flags)
  80.       continue;
  81.  
  82.     for (j = 0; j < 8; j++)
  83.       if (t->vecs[0][j] != tex->vecs[0][j])
  84.     break;
  85.     if (j != 8)
  86.       continue;
  87.  
  88.     return i;
  89.   }
  90.  
  91.   /* allocate a new texture */
  92.   if (bspMem->shared.quake1.numtexinfo == bspMem->shared.quake1.max_numtexinfo)
  93.     ExpandClusters(bspMem, LUMP_TEXINFO);
  94.   bspMem->shared.quake1.texinfo[i] = *t;
  95.   bspMem->shared.quake1.numtexinfo++;
  96.  
  97.   return i;
  98. }
  99.  
  100. /*JIM */
  101. struct entity *FindEntityWithKeyPair(__memBase, char *key, char *value)
  102. {
  103.   struct entity *ent;
  104.   struct epair *ep;
  105.   int i;
  106.  
  107.   /*for(i = 0, ent = bspMem->mapentities; i < bspMem->nummapentities; i++, ent++) { */
  108.   for (i = 0; i < bspMem->nummapentities; i++) {
  109.     ent = &bspMem->mapentities[i];
  110.     for (ep = ent->epairs; ep; ep = ep->next) {
  111.       if (!__strcmp(ep->key, key)) {
  112.     if (!__strcmp(ep->value, value)) {
  113.       return ent;
  114.     }
  115.     break;
  116.       }
  117.     }
  118.   }
  119.   return NULL;
  120. }
  121.  
  122. struct entity *FindTargetEntity(__memBase, char *target)
  123. {
  124.   int i;
  125.  
  126.   for (i = 0; i < bspMem->nummapentities; i++)
  127.     if (!__strcmp(bspMem->mapentities[i].targetname, target))
  128.       return &bspMem->mapentities[i];
  129.  
  130.   return NULL;
  131. }
  132.  
  133. struct entity *FindEntityWithModel(__memBase, int modnum)
  134. {
  135.   int i;
  136.   char *s;
  137.   char name[16];
  138.  
  139.   sprintf(name, "*%i", modnum);
  140.   /* search the entities for one using modnum */
  141.   for (i = 0; i < bspMem->nummapentities; i++) {
  142.     s = ValueForKey(&bspMem->mapentities[i], "model");
  143.     if (!__strcmp(s, name))
  144.       return &bspMem->mapentities[i];
  145.   }
  146.  
  147.   return &bspMem->mapentities[0];
  148. }
  149.  
  150. /*============================================================================ */
  151.  
  152. void StartTokenParsing(char *data)
  153. {
  154.   scriptline = 1;
  155.   script_p = data;
  156.   unget = FALSE;
  157. }
  158.  
  159. bool GetToken(bool crossline)
  160. {
  161.   char *token_p;
  162.  
  163.   if (unget)                            /* is a token allready waiting? */
  164.     return TRUE;
  165.  
  166.   /* skip space */
  167. skipspace:
  168.   while (*script_p <= 32) {
  169.     if (!*script_p) {
  170.       if (!crossline)
  171.     Error("Line %i is incomplete", scriptline);
  172.       return FALSE;
  173.     }
  174.     if (*script_p++ == '\n') {
  175.       if (!crossline)
  176.     Error("Line %i is incomplete", scriptline);
  177.       scriptline++;
  178.     }
  179.   }
  180.  
  181.   if (script_p[0] == '/' && script_p[1] == '/') {        /* comment field */
  182.     if (!crossline)
  183.       Error("Line %i is incomplete\n", scriptline);
  184.     while (*script_p++ != '\n')
  185.       if (!*script_p) {
  186.     if (!crossline)
  187.       Error("Line %i is incomplete", scriptline);
  188.     return FALSE;
  189.       }
  190.     goto skipspace;
  191.   }
  192.  
  193.   /* copy token */
  194.   token_p = token;
  195.  
  196.   if (*script_p == '"') {
  197.     script_p++;
  198.     while (*script_p != '"') {
  199.       if (!*script_p)
  200.     Error("EOF inside quoted token");
  201.       *token_p++ = *script_p++;
  202.       if (token_p > &token[MAXTOKEN - 1])
  203.     Error("Token too large on line %i", scriptline);
  204.     }
  205.     script_p++;
  206.   }
  207.   else
  208.     while (*script_p > 32) {
  209.       *token_p++ = *script_p++;
  210.       if (token_p > &token[MAXTOKEN - 1])
  211.     Error("Token too large on line %i", scriptline);
  212.     }
  213.  
  214.   *token_p = 0;
  215.  
  216.   return TRUE;
  217. }
  218.  
  219. void UngetToken(void)
  220. {
  221.   unget = TRUE;
  222. }
  223.  
  224. /*============================================================================ */
  225.  
  226. /*
  227.  * =================
  228.  * ParseEpair
  229.  * =================
  230.  */
  231. void ParseEpair(void)
  232. {
  233.   struct epair *e;
  234.  
  235.   if (!(e = (struct epair *)tmalloc(sizeof(struct epair))))
  236.       Error(failed_memory, sizeof(struct epair), "epair");
  237.  
  238.   e->next = mapent->epairs;
  239.   mapent->epairs = e;
  240.  
  241.   if (__strlen(token) >= MAX_KEY - 1)
  242.     Error("ParseEpar: token too long");
  243.   if (!(e->key = smalloc(token)))
  244.     Error(failed_memoryunsize, "key");
  245.   GetToken(FALSE);
  246.   if (__strlen(token) >= MAX_VALUE - 1)
  247.     Error("ParseEpar: token too long");
  248.   if (!(e->value = smalloc(token)))
  249.     Error(failed_memoryunsize, "value");
  250. }
  251.  
  252. /*============================================================================ */
  253.  
  254. /*
  255.  * ==================
  256.  * textureAxisFromPlane
  257.  * ==================
  258.  */
  259. void TextureAxisFromPlane(struct plane *pln, vec3_t xv, vec3_t yv)
  260. {
  261.   short int bestaxis;
  262.   float dot, best;
  263.   short int i;
  264.  
  265.   best = 0;
  266.   bestaxis = 0;
  267.  
  268.   for (i = 0; i < 6; i++) {
  269.     dot = DotProduct(pln->normal, baseaxis[i * 3]);
  270.     if (dot > best) {
  271.       best = dot;
  272.       bestaxis = i;
  273.     }
  274.   }
  275.  
  276.   VectorCopy(baseaxis[bestaxis * 3 + 1], xv);
  277.   VectorCopy(baseaxis[bestaxis * 3 + 2], yv);
  278. }
  279.  
  280. /*============================================================================= */
  281.  
  282. static void GetEdges(__memBase, register int ledge, register struct dedge_t *edge)
  283. {
  284.   if (bspMem->shared.quake1.dsurfedges[ledge] > 0) {
  285.     *edge = bspMem->shared.quake1.dedges[bspMem->shared.quake1.dsurfedges[ledge]];
  286.   }
  287.   else {
  288.     edge->v[0] = bspMem->shared.quake1.dedges[-(bspMem->shared.quake1.dsurfedges[ledge])].v[1];
  289.     edge->v[1] = bspMem->shared.quake1.dedges[-(bspMem->shared.quake1.dsurfedges[ledge])].v[0];
  290.   }
  291. }
  292.  
  293. static struct mface *AddFace(register struct mbrush *b, register int t, register vec3_t planepts0, register vec3_t planepts1, register vec3_t planepts2)
  294. {
  295.   struct mface *f;
  296.   vec3_t t1, t2, t3;
  297.   short int j;
  298.  
  299.   if (!(f = (struct mface *)tmalloc(sizeof(struct mface))))
  300.       Error(failed_memory, sizeof(struct mface), "mface");
  301.  
  302.   /* convert to a vector / dist plane */
  303.   for (j = 0; j < 3; j++) {
  304.     t1[j] = planepts0[j] - planepts1[j];
  305.     t2[j] = planepts2[j] - planepts1[j];
  306.     t3[j] = planepts1[j];
  307.   }
  308.  
  309.   CrossProduct(t1, t2, f->plane.normal);
  310.   if (VectorZero(f->plane.normal)) {
  311.     eprintf("brush plane with no normal\n");
  312.     tfree(f);
  313.     f = 0;
  314.   }
  315.   else {
  316.     f->next = b->faces;
  317.     b->faces = f;
  318.  
  319.     VectorNormalize(f->plane.normal);
  320.     f->plane.dist = DotProduct(t3, f->plane.normal);
  321.     f->texinfo = t;
  322.     VectorCopy(planepts0, f->p0);
  323.     VectorCopy(planepts1, f->p1);
  324.     VectorCopy(planepts2, f->p2);
  325.   }
  326.  
  327.   return f;
  328. }
  329.  
  330. static void ParseFace(__memBase, register struct entity *bspent, register int face)
  331. {
  332.   short int numfaceedges;
  333.   short int firstfaceedge;
  334.   int ledge, ledge2;
  335.   struct dedge_t edges[MAXEDGES];
  336.   struct dvertex_t vert_beg[MAXEDGES];
  337.   struct dvertex_t vert_end[MAXEDGES];
  338.   vec3_t normal, v1, v2, v3;
  339.   int t = bspMem->shared.quake1.dfaces[face].texinfo;
  340.   struct mbrush *b;
  341.  
  342.   if (!(b = (struct mbrush *)tmalloc(sizeof(struct mbrush))))
  343.       Error(failed_memory, sizeof(struct mbrush), "mbrush");
  344.  
  345.   nummapbrushes++;
  346.   b->next = bspent->brushes;
  347.   bspent->brushes = b;
  348.  
  349.   numfaceedges = bspMem->shared.quake1.dfaces[face].numedges;
  350.   firstfaceedge = bspMem->shared.quake1.dfaces[face].firstedge;
  351.  
  352.   if (numfaceedges < 3)
  353.     Error("too few edges for face");
  354.  
  355.   if (numfaceedges > MAXEDGES)
  356.     Error("too many edges for face");
  357.  
  358.   for (ledge2 = ledge = 0; ledge < numfaceedges; ledge++, ledge2++) {
  359.     GetEdges(bspMem, ledge2 + firstfaceedge, &edges[ledge]);
  360.     vert_beg[ledge] = bspMem->shared.quake1.dvertexes[edges[ledge].v[0]];
  361.     vert_end[ledge] = bspMem->shared.quake1.dvertexes[edges[ledge].v[1]];
  362.  
  363.     if (VectorCompare(vert_beg[ledge].point, vert_end[ledge].point))
  364.       ledge--;
  365.   }
  366.  
  367.   VectorCopy(bspMem->shared.quake1.dplanes[bspMem->shared.quake1.dfaces[face].planenum].normal, normal);
  368.   VectorScale(normal, (float)2, normal);
  369.  
  370.   if (!bspMem->shared.quake1.dfaces[face].side)
  371.     VectorInverse(normal);
  372.  
  373.   for (ledge2 = 1; ledge2 < numfaceedges - 2; ledge2++) {
  374.     VectorSubtract(vert_end[0].point, vert_beg[0].point, v1);
  375.     VectorSubtract(vert_end[ledge2].point, vert_beg[ledge2].point, v2);
  376.     VectorNormalize(v1);
  377.     VectorNormalize(v2);
  378.  
  379.     if (!VectorCompare(v1, v2))
  380.       break;
  381.   }
  382.  
  383.   AddFace(b, t, vert_beg[0].point, vert_end[0].point, vert_end[ledge2].point);
  384.  
  385.   for (ledge = 0; ledge < numfaceedges; ledge++) {
  386.     if (ledge == 0) {
  387.       VectorSubtract(vert_end[numfaceedges - 1].point, vert_beg[numfaceedges - 1].point, v1);
  388.       VectorSubtract(vert_end[ledge].point, vert_beg[ledge].point, v2);
  389.       VectorNormalize(v1);
  390.       VectorNormalize(v2);
  391.       if (VectorCompare(v1, v2))
  392.     continue;
  393.     }
  394.     else {
  395.       VectorSubtract(vert_end[ledge - 1].point, vert_beg[ledge - 1].point, v1);
  396.       VectorSubtract(vert_end[ledge].point, vert_beg[ledge].point, v2);
  397.       VectorNormalize(v1);
  398.       VectorNormalize(v2);
  399.       if (VectorCompare(v1, v2))
  400.     continue;
  401.     }
  402.  
  403.     VectorAdd(vert_end[ledge].point, normal, v2);
  404.     AddFace(b, t, vert_end[ledge].point, vert_beg[ledge].point, v2);
  405.   }
  406.  
  407.   VectorAdd(vert_beg[0].point, normal, v2);
  408.   VectorAdd(vert_end[0].point, normal, v1);
  409.   VectorAdd(vert_end[ledge2].point, normal, v3);
  410.   AddFace(b, t, v1, v2, v3);
  411. }
  412.  
  413. /*============================================================================= */
  414.  
  415. /*
  416.  * fake proper texture vectors from QuakeEd style
  417.  */
  418. int MakeTexinfo(__memBase, char *texname, struct mface *f, float *scale, float rotate, float *shift)
  419. {
  420.   struct texinfo tx;
  421.   vec3_t vecs[2];
  422.   int sv, tv;
  423.   float ang, sinv, cosv;
  424.   float ns, nt;
  425.   short int i, j;
  426.  
  427.   __bzero(&tx, sizeof(tx));
  428.   tx.miptex = FindMiptex(bspMem, texname);
  429.   tfree(texname);
  430.  
  431.   TextureAxisFromPlane(&f->plane, vecs[0], vecs[1]);
  432.  
  433.   if (!scale[0])
  434.     scale[0] = 1;
  435.   if (!scale[1])
  436.     scale[1] = 1;
  437.  
  438.   /* rotate axis */
  439.   if (rotate == 0) {
  440.     sinv = 0;
  441.     cosv = 1;
  442.   }
  443.   else if (rotate == 90) {
  444.     sinv = 1;
  445.     cosv = 0;
  446.   }
  447.   else if (rotate == 180) {
  448.     sinv = 0;
  449.     cosv = -1;
  450.   }
  451.   else if (rotate == 270) {
  452.     sinv = -1;
  453.     cosv = 0;
  454.   }
  455.   else {
  456.     ang = rotate / 180 * Q_PI;
  457.     sinv = sin(ang);
  458.     cosv = cos(ang);
  459.   }
  460.  
  461.   if (vecs[0][0])
  462.     sv = 0;
  463.   else if (vecs[0][1])
  464.     sv = 1;
  465.   else
  466.     sv = 2;
  467.  
  468.   if (vecs[1][0])
  469.     tv = 0;
  470.   else if (vecs[1][1])
  471.     tv = 1;
  472.   else
  473.     tv = 2;
  474.  
  475.   for (i = 0; i < 2; i++) {
  476.     ns = cosv * vecs[i][sv] - sinv * vecs[i][tv];
  477.     nt = sinv * vecs[i][sv] + cosv * vecs[i][tv];
  478.     vecs[i][sv] = ns;
  479.     vecs[i][tv] = nt;
  480.   }
  481.  
  482.   for (i = 0; i < 2; i++)
  483.     for (j = 0; j < 3; j++)
  484.       tx.vecs[i][j] = vecs[i][j] / scale[i];
  485.  
  486.   tx.vecs[0][3] = shift[0];
  487.   tx.vecs[1][3] = shift[1];
  488.  
  489.   /* unique the texinfo */
  490.   return FindTexinfo(bspMem, &tx);
  491. }
  492.  
  493. /*
  494.  * =================
  495.  * ParseBrush
  496.  * =================
  497.  */
  498. void ParseBrush(__memBase)
  499. {
  500.   struct mbrush *b;
  501.   struct mface *f, *f2;
  502.   vec3_t planepts[3];
  503.   short int i, j;
  504.   vec_t d;
  505.   float shift[2], rotate, scale[2];
  506.   char *texname;
  507.  
  508.   if (!(b = (struct mbrush *)tmalloc(sizeof(struct mbrush))))
  509.       Error(failed_memory, sizeof(struct mbrush), "mbrush");
  510.  
  511.   nummapbrushes++;
  512.   b->next = mapent->brushes;
  513.   mapent->brushes = b;
  514.  
  515.   do {
  516.     if (!GetToken(TRUE))
  517.       break;
  518.     if (!__strcmp(token, "}"))
  519.       break;
  520.  
  521.     /* read the three point plane definition */
  522.     for (i = 0; i < 3; i++) {
  523.       if (i != 0)
  524.     GetToken(TRUE);
  525.       if (__strcmp(token, "("))
  526.     Error("parsing brush");
  527.  
  528.       for (j = 0; j < 3; j++) {
  529.     GetToken(FALSE);
  530.     planepts[i][j] = atof(token);
  531.       }
  532.  
  533.       GetToken(FALSE);
  534.       if (__strcmp(token, ")"))
  535.     Error("parsing brush");
  536.  
  537.     }
  538.  
  539.     /* read the texturedef */
  540.     GetToken(FALSE);
  541.     texname = smalloc(token);
  542.     GetToken(FALSE);
  543.     shift[0] = atof(token);
  544.     GetToken(FALSE);
  545.     shift[1] = atof(token);
  546.     GetToken(FALSE);
  547.     rotate = atof(token);
  548.     GetToken(FALSE);
  549.     scale[0] = atof(token);
  550.     GetToken(FALSE);
  551.     scale[1] = atof(token);
  552.  
  553.     /* if the three points are all on a previous plane, it is a */
  554.     /* duplicate plane */
  555.     for (f2 = b->faces; f2; f2 = f2->next) {
  556.       for (i = 0; i < 3; i++) {
  557.     d = DotProduct(planepts[i], f2->plane.normal) - f2->plane.dist;
  558.     if (d < -ON_EPSILON || d > ON_EPSILON)
  559.       break;
  560.       }
  561.       if (i == 3)
  562.     break;
  563.     }
  564.     if (f2) {
  565.       eprintf("brush with duplicate plane\n");
  566.       continue;
  567.     }
  568.  
  569.     if ((f = AddFace(b, 0, planepts[0], planepts[1], planepts[2])))
  570.       f->texinfo = MakeTexinfo(bspMem, texname, f, scale, rotate, shift);
  571.   } while (1);
  572. }
  573.  
  574. /*
  575.  * ================
  576.  * ParseEntity
  577.  * ================
  578.  */
  579. bool ParseEntity(__memBase)
  580. {
  581.   if (!GetToken(TRUE))
  582.     return FALSE;
  583.  
  584.   if (__strcmp(token, "{"))
  585.     Error("ParseEntity: { not found");
  586.  
  587.   if (bspMem->nummapentities == bspMem->max_nummapentities)
  588.     ExpandClusters(bspMem, MAP_ENTITIES);
  589.   mapent = &bspMem->mapentities[bspMem->nummapentities];
  590.   bspMem->nummapentities++;
  591.  
  592.   do {
  593.     if (!GetToken(TRUE))
  594.       Error("ParseEntity: EOF without closing brace");
  595.     if (!__strcmp(token, "}"))
  596.       break;
  597.     if (!__strcmp(token, "{"))
  598.       ParseBrush(bspMem);
  599.     else
  600.       ParseEpair();
  601.   } while (1);
  602.  
  603.   /*
  604.    * for all 
  605.    */
  606.   GetVectorForKey(mapent, "origin", mapent->origin);
  607.   mapent->classname = ValueForKey(mapent, "classname");
  608.   mapent->target = ValueForKey(mapent, "target");
  609.   mapent->targetname = ValueForKey(mapent, "targetname");
  610.  
  611.   /*
  612.    * special for qbsp+light+vis in one part 
  613.    */
  614.   if (bspMem->mapOptions & MAP_LOADLIGHTS) {
  615.     if (!(mapent->light = FloatForKeyN(mapent, "light")))
  616.       if (!(mapent->light = FloatForKey(mapent, "_light")))
  617.     mapent->light = 0;
  618.     if (!(mapent->style = FloatForKey(mapent, "style")))
  619.       if (!(mapent->style = FloatForKey(mapent, "_style")))
  620.     mapent->style = 0;
  621.     mapent->angle = FloatForKey(mapent, "angle");
  622.  
  623.     if (!__strncmp(mapent->classname, "light", 5)) {
  624.       if (!mapent->light)
  625.     mapent->light = DEFAULTLIGHTLEVEL;
  626.  
  627.       /*if (!mapent->classname[5])) { */
  628.       if (mapent->targetname[0] && !mapent->style) {
  629.     char s[256];
  630.  
  631.     mapent->style = LightStyleForTargetname(mapent->targetname, TRUE);
  632.     sprintf(s, "%i", mapent->style);
  633.     SetKeyValue(mapent, "style", s);
  634.       }
  635.       /*} */
  636.     }
  637.   }
  638.   return TRUE;
  639. }
  640.  
  641. /*
  642.  * ================
  643.  * LoadMapFile
  644.  * ================
  645.  */
  646. bool LoadMapFile(__memBase, char *mapBuf)
  647. {
  648.   StartTokenParsing(mapBuf);
  649.   bspMem->nummapentities = 0;
  650.  
  651.   mprintf("----- LoadMapFile -------\n");
  652.  
  653.   while (ParseEntity(bspMem)) {
  654.   }
  655.   MatchTargets(bspMem);
  656.  
  657.   if (nummapbrushes)
  658.     mprintf("%5i brushes\n", nummapbrushes);
  659.   if (bspMem->nummapentities)
  660.     mprintf("%5i entities\n", bspMem->nummapentities);
  661.   if (bspMem->nummaptexstrings)
  662.     mprintf("%5i miptex\n", bspMem->nummaptexstrings);
  663.   if (bspMem->shared.quake1.numtexinfo)
  664.     mprintf("%5i texinfo\n", bspMem->shared.quake1.numtexinfo);
  665.  
  666.   return TRUE;
  667. }
  668.  
  669. /*
  670.  * ================
  671.  * SaveMapFile
  672.  * ================
  673.  */
  674. bool SaveMapFile(__memBase, FILE * outFile)
  675. {
  676.   struct entity *ent;
  677.   struct epair *ep;
  678.   struct mbrush *b;
  679.   struct mface *f;
  680.   int i;
  681.   struct dmiptexlump_t *head_miptex = (struct dmiptexlump_t *)bspMem->shared.quake1.dtexdata;
  682.  
  683.   mprintf("----- SaveMapFile -------\n");
  684.  
  685.   for (i = 0, ent = bspMem->mapentities; i < bspMem->nummapentities; i++, ent++) {
  686.     fprintf(outFile, "{\n");
  687.  
  688.     for (ep = ent->epairs; ep; ep = ep->next)
  689.       if (__strcmp(ep->key, "model"))
  690.     fprintf(outFile, "  \"%s\" \"%s\"\n", ep->key, ep->value);
  691.  
  692.     for (b = ent->brushes; b; b = b->next) {
  693.       fprintf(outFile, "  {\n");
  694.  
  695.       for (f = b->faces; f; f = f->next) {
  696.     struct texinfo *texinfo = &bspMem->shared.quake1.texinfo[f->texinfo];
  697.     char *miptexname;
  698.  
  699.     if (head_miptex)                    /* for an allready compiled map */
  700.       miptexname = ((struct mipmap *)(bspMem->shared.quake1.dtexdata + head_miptex->dataofs[texinfo->miptex]))->name;
  701.     else if (bspMem->maptexstrings)                /* for an uncompiled map */
  702.       miptexname = bspMem->maptexstrings[texinfo->miptex];
  703.     else                            /* for unknown states */
  704.       miptexname = "unknown\0";
  705.  
  706.     /*here must calc x_off y_off rotation x_scale y_scale from p_texinfo->vecs ! */
  707.     fprintf(outFile, "    ( %g %g %g ) ( %g %g %g ) ( %g %g %g ) %s %g %g %g %g %g\n",
  708.         f->p0[0], f->p0[1], f->p0[2], f->p1[0], f->p1[1], f->p1[2], f->p2[0], f->p2[1], f->p2[2], miptexname, texinfo->vecs[0][3], texinfo->vecs[1][3], 0.0, 1.0, 1.0);
  709.       }
  710.  
  711.       fprintf(outFile, "  }\n");
  712.     }
  713.  
  714.     fprintf(outFile, "}\n");
  715.     mprogress(bspMem->nummapentities, i + 1);
  716.   }
  717.  
  718.   return TRUE;
  719. }
  720.  
  721. /*
  722.  * ================
  723.  * LoadBSPFile
  724.  * ================
  725.  */
  726. bool LoadBSPFile(__memBase)
  727. {
  728.   struct entity *ent;
  729.   struct epair *ep;
  730.   int face;
  731.   int i;
  732.  
  733.   mprintf("----- LoadBSPFile -------\n");
  734.  
  735.   for (i = 0, ent = bspMem->mapentities; i < bspMem->nummapentities; i++, ent++) {
  736.     int modelfaces = 0;
  737.     int numfaces = 0;
  738.  
  739.     for (ep = ent->epairs; ep; ep = ep->next) {
  740.       if (!__strcmp(ep->key, "model")) {
  741.     int model = atoi(ep->value);
  742.  
  743.     numfaces = bspMem->shared.quake1.dmodels[model].numfaces;
  744.     modelfaces = bspMem->shared.quake1.dmodels[model].firstface;
  745.       }
  746.  
  747.       if (!__strcmp(ep->key, "classname") && !__strcmp(ep->value, "worldspawn")) {
  748.     numfaces = bspMem->shared.quake1.dmodels[0].numfaces;
  749.     modelfaces = bspMem->shared.quake1.dmodels[0].firstface;
  750.       }
  751.     }
  752.     if (numfaces)
  753.       for (face = 0; face < numfaces; face++, modelfaces++)
  754.     ParseFace(bspMem, ent, modelfaces);
  755.     mprogress(bspMem->nummapentities, i + 1);
  756.   }
  757.  
  758.   mprintf("%5i brushes\n", nummapbrushes);
  759.  
  760.   return TRUE;
  761. }
  762.  
  763. /*
  764.  * ==============================================================================
  765.  * 
  766.  * ENTITY FILE PARSING
  767.  * 
  768.  * If a light has a targetname, generate a unique style in the 32-63 range
  769.  * ==============================================================================
  770.  */
  771.  
  772. int LightStyleForTargetname(char *targetname, bool alloc)
  773. {
  774.   int i;
  775.  
  776.   for (i = 0; i < numlighttargets; i++)
  777.     if (!__strcmp(lighttargets[i], targetname))
  778.       return 32 + i;
  779.   if (!alloc)
  780.     return -1;
  781.   __strcpy(lighttargets[i], targetname);
  782.   numlighttargets++;
  783.   return numlighttargets - 1 + 32;
  784. }
  785.  
  786. /*
  787.  * ==================
  788.  * MatchTargets
  789.  * ==================
  790.  */
  791. void MatchTargets(__memBase)
  792. {
  793.   int i;
  794.  
  795.   for (i = 0; i < bspMem->nummapentities; i++) {
  796.     if (bspMem->mapentities[i].target[0]) {
  797.       if (!(bspMem->mapentities[i].targetent = FindTargetEntity(bspMem, bspMem->mapentities[i].target)))
  798.     eprintf("entity at (%i,%i,%i) (%s) has unmatched target\n", (int)bspMem->mapentities[i].origin[0], (int)bspMem->mapentities[i].origin[1], (int)bspMem->mapentities[i].origin[2], bspMem->mapentities[i].classname);
  799.       else {
  800.     /* set the style on the source ent for switchable lights */
  801.     if (bspMem->mapentities[i].targetent->style) {
  802.       char s[256];
  803.  
  804.       bspMem->mapentities[i].style = bspMem->mapentities[i].targetent->style;
  805.       sprintf(s, "%i", bspMem->mapentities[i].style);
  806.       SetKeyValue(&bspMem->mapentities[i], "style", s);
  807.     }
  808.       }
  809.     }
  810.   }
  811. }
  812.  
  813. void WriteEntitiesToString(__memBase)
  814. {
  815.   char *buf, *end;
  816.   struct epair *ep;
  817.   char line[128];
  818.   int i;
  819.  
  820.   buf = bspMem->shared.quake1.dentdata;
  821.   end = bspMem->shared.quake1.dentdata + bspMem->shared.quake1.max_entdatasize - SAVE_BACK;
  822.   *buf = 0;
  823.  
  824.   for (i = 0; i < bspMem->nummapentities; i++) {
  825.     ep = bspMem->mapentities[i].epairs;
  826.     if (!ep)
  827.       continue;                            /* ent got removed */
  828.  
  829.     __strcat(buf, "{\n");
  830.     buf += 2;
  831.  
  832.     /*
  833.      * if free at this use "ep = FreeEpair(ep)" 
  834.      */
  835.     for (ep = bspMem->mapentities[i].epairs; ep; ep = ep->next) {
  836.       sprintf(line, "\"%s\" \"%s\"\n", ep->key, ep->value);
  837.  
  838.       if ((buf + __strlen(line)) >= end) {
  839.     int len = buf - bspMem->shared.quake1.dentdata;
  840.  
  841.     ExpandClusters(bspMem, LUMP_ENTITIES);
  842.     end = bspMem->shared.quake1.dentdata + bspMem->shared.quake1.max_entdatasize - SAVE_BACK;
  843.     buf = bspMem->shared.quake1.dentdata + len;
  844.       }
  845.  
  846.       __strcat(buf, line);
  847.       buf += __strlen(line);
  848.     }
  849.     __strcat(buf, "}\n");
  850.     buf += 2;
  851.   }
  852.   bspMem->shared.quake1.entdatasize = buf - bspMem->shared.quake1.dentdata + 1;
  853. }
  854.  
  855. void PrintEntity(struct entity *ent)
  856. {
  857.   struct epair *ep;
  858.  
  859.   for (ep = ent->epairs; ep; ep = ep->next)
  860.     mprintf("%20s : %s\n", ep->key, ep->value);
  861.   mprintf("-------------------- - --------------------\n");
  862.   mprintf("%20s : %s\n", "classname", ent->classname);
  863.   mprintf("%20s : %g\n", "angle", ent->angle);
  864.   mprintf("%20s : ( %g %g %g )\n", "origin", ent->origin[0], ent->origin[1], ent->origin[2]);
  865.   mprintf("%20s : %d\n", "light", ent->light);
  866.   mprintf("%20s : %d\n", "style", ent->style);
  867.   mprintf("%20s : %s\n", "target", ent->target);
  868.   mprintf("%20s : %s\n", "targetname", ent->targetname);
  869. }
  870.  
  871. char *ValueForKey(struct entity *ent, char *key)
  872. {
  873.   struct epair *ep;
  874.  
  875.   for (ep = ent->epairs; ep; ep = ep->next)
  876.     if (!__strcmp(ep->key, key))
  877.       return ep->value;
  878.   return "";
  879. }
  880.  
  881. char *ValueForKeyN(struct entity *ent, char *key)
  882. {
  883.   struct epair *ep;
  884.   int len = __strlen(key);
  885.  
  886.   for (ep = ent->epairs; ep; ep = ep->next)
  887.     if (!__strncmp(ep->key, key, len))
  888.       return ep->value;
  889.   return "";
  890. }
  891.  
  892. void SetKeyValue(struct entity *ent, char *key, char *value)
  893. {
  894.   struct epair *ep;
  895.  
  896.   for (ep = ent->epairs; ep; ep = ep->next)
  897.     if (!__strcmp(ep->key, key)) {
  898.       tfree(ep->value);
  899.       ep->value = smalloc(value);
  900.       return;
  901.     }
  902.   if (!(ep = (struct epair *)tmalloc(sizeof(*ep))))
  903.     Error(failed_memory, sizeof(struct epair), "epair");
  904.   ep->next = ent->epairs;
  905.   ent->epairs = ep;
  906.   if (!(ep->key = smalloc(key)))
  907.     Error(failed_memoryunsize, "key");
  908.   if (!(ep->value = smalloc(value)))
  909.     Error(failed_memoryunsize, "value");
  910. }
  911.  
  912. float FloatForKey(struct entity *ent, char *key)
  913. {
  914.   char *k;
  915.   float ret = 0;
  916.  
  917.   if ((k = ValueForKey(ent, key)))
  918.     if (k[0])
  919.       ret = atof(k);
  920.  
  921.   return ret;
  922. }
  923.  
  924. float FloatForKeyN(struct entity *ent, char *key)
  925. {
  926.   char *k;
  927.   float ret = 0;
  928.  
  929.   if ((k = ValueForKeyN(ent, key)))
  930.     if (k[0])
  931.       ret = atof(k);
  932.  
  933.   return ret;
  934. }
  935.  
  936. void GetVectorForKey(struct entity *ent, char *key, vec3_t vec)
  937. {
  938.   char *k;
  939.  
  940.   vec[0] = vec[1] = vec[2] = 0;
  941.   /* scanf into doubles, then assign, so it is vec_t size independent */
  942.   if ((k = ValueForKey(ent, key)))
  943.     if (k[0])
  944.       if (sscanf(k, "%g %g %g", &vec[0], &vec[1], &vec[2]) != 3)
  945.     Error("GetVectorForKey: not 3 points as expected: %g %g %g (%s = %s)!\n", vec[0], vec[1], vec[2], key, k);
  946. }
  947.